Skip to content

feat: ENABLE_<CLI> toggles + default-deny for Gemini, OpenCode, Hermes#30

Open
dgokeeffe wants to merge 1 commit intomainfrom
feat/cli-toggles
Open

feat: ENABLE_<CLI> toggles + default-deny for Gemini, OpenCode, Hermes#30
dgokeeffe wants to merge 1 commit intomainfrom
feat/cli-toggles

Conversation

@dgokeeffe
Copy link
Copy Markdown
Collaborator

@dgokeeffe dgokeeffe commented May 7, 2026

Summary

Introduce per-CLI install toggles (ENABLE_CODEX, ENABLE_OPENCODE, ENABLE_GEMINI, mirroring the existing ENABLE_HERMES), and default Gemini, OpenCode, and Hermes to OFF. A fresh CoDA deploy now ships with two CLIs running by default — Claude Code and Codex.

Security posture rationale

The App container holds the rotated workspace PAT (~/.databrickscfg, written by pat_rotator.py every 10 min) and the user's repos under ~/projects/. Any process that runs in there has effective full workspace access. That puts a higher bar on "what installs by default" than for local dev tools.

CLI Default Why
Claude Code (Anthropic) enabled (always-on; not toggleable) Primary CLI; vendor with mature signing / SBOM / advisory disclosure
Codex (OpenAI) enabled by default Same supply-chain tier as Anthropic
Gemini (Google) opt-in Vendor has signing infra but lags upstream on SBOM/advisory pipelines for the CLI specifically
OpenCode (community/anomalyco fork) opt-in No equivalent enterprise supply-chain process
Hermes (Nous Research) opt-in No equivalent enterprise supply-chain process

Operators who want the previous five-CLI experience flip the three toggles back to "true" in their own app.yaml override.

Behavioural change for existing deploys

Operators upgrading to this version see Gemini/OpenCode/Hermes disappear unless they explicitly opt in. This is intentional — see rationale above — but worth calling out to reviewers as the substantive UX delta.

Mechanics

  • 4-line gate at the top of each setup_*.py: read env var, exit 0 if false. Exact pattern reuses setup_hermes.py's existing structure.
  • app.yaml documents all four toggles in one comment block.
  • setup_claude.py is intentionally not gated — it bootstraps ~/projects/ and writes app-wide MCP config that the other CLIs reuse.

Test plan

  • Deploy to a workspace; confirm only Claude + Codex install steps run during boot
  • In app.yaml, set ENABLE_GEMINI=true, redeploy; confirm Gemini installs
  • Same for ENABLE_OPENCODE=true and ENABLE_HERMES=true
  • Run pytest tests/ — toggle-introduction tests should still pass
  • Smoke-test the existing already-enabled flow: launch Claude Code and Codex from the App terminal, verify both authenticate against the workspace

Follow-ups (out of scope for this PR)

  • Flip the Python-level fallback defaults to "false" too, so a missing app.yaml also fails-closed. Currently each setup_*.py reads os.environ.get("ENABLE_X", "true") which is fail-open if app.yaml is absent.
  • Add audit GH Action coverage for the still-enabled CLIs (Codex's @openai/codex is already in dependency-audit.yml; Claude Code is installed via curl so out of npm-audit scope).

This pull request and its description were written by Isaac.

Introduce per-CLI install toggles for Codex, OpenCode, Gemini, Hermes
(replicating the existing ENABLE_HERMES pattern across the other three
secondary CLIs), and default the three less-vetted CLIs to OFF.

Security posture rationale (the substantive change vs. the original
"toggles only" PR): the App container holds the rotated workspace PAT
(~/.databrickscfg, written by pat_rotator.py) and all repos under
~/projects/, so any process that runs there has effective full
workspace access. That makes the supply-chain bar for runtime CLIs
higher than for a local dev tool. Claude Code (Anthropic) and Codex
(OpenAI) ship from vendors with mature signing / SBOM / advisory
pipelines and stay enabled by default. Gemini, OpenCode, and Hermes
don't have equivalent supply-chain processes; they become opt-in.
Operators flip ENABLE_<CLI>=true in app.yaml to install them.

Note that this changes the default user experience: a fresh deploy
ships with two CLIs (Claude, Codex) instead of five. Operators who
want the previous behaviour can flip the three toggles back in their
own app.yaml override.

Mechanics:
- 4-line gate at the top of each setup_*.py: read env var, exit 0 if false
- app.yaml documents all four toggles in one comment block

Claude Code stays always-on — it's the primary CLI and setup_claude.py
also creates ~/projects and writes app-wide MCP config that other agents
can re-use. Disentangling those would expand scope; can be a follow-up.

Smoke-tested locally:
  $ ENABLE_CODEX=false python3 setup_codex.py
  ENABLE_CODEX=false — skipping Codex CLI setup
  $ # exit 0, no further side effects

Follow-ups (out of scope):
- Flip the Python-level defaults to "false" too, so a missing app.yaml
  also fails-closed. Currently each setup_*.py reads
  os.environ.get("ENABLE_X", "true") which is a fail-open default.
- Add an audit GH Action equivalent for the still-enabled CLIs against
  npm advisories (Codex's @openai/codex via dependency-audit.yml is
  already covered).

Co-authored-by: Isaac
@dgokeeffe dgokeeffe force-pushed the feat/cli-toggles branch from 8d44956 to 513193f Compare May 7, 2026 13:57
@dgokeeffe dgokeeffe changed the title feat: ENABLE_<CLI>=false toggles for Codex / OpenCode / Gemini feat: ENABLE_<CLI> toggles + default-deny for Gemini, OpenCode, Hermes May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant